package com.zhou.org.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhou.util.NumberUtil;
import com.zhou.util.ObjectUtil;
import com.zhou.org.common.EnumConstant;
import com.zhou.org.common.OrgUtil;
import com.zhou.org.common.RightUtil;
import com.zhou.org.dao.Org;
import com.zhou.org.dao.OrgRelation;
import com.zhou.org.dao.User;
import com.zhou.org.dto.OrgDragDto;
import com.zhou.org.dto.OrgDto;
import com.zhou.org.dto.OrgQueryDto;
import com.zhou.org.dto.OrgRelationDelDto;
import com.zhou.org.mapper.OrgMapper;
import com.zhou.org.mapper.OrgRelationMapper;
import com.zhou.org.mapper.RightMapper;
import com.zhou.org.mapper.UserMapper;
import com.zhou.org.model.OrgTree;
import com.zhou.org.service.OrgService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lang.zhou
 * @since 2022-08-23
 */
@Slf4j
@Service
public class OrgServiceImpl extends ServiceImpl<OrgMapper, Org> implements OrgService {

    private final RightMapper rightMapper;
    private final UserMapper userMapper;
    private final OrgRelationMapper orgRelationMapper;
    private List<OrgTree> tree ;
    @Autowired
    public OrgServiceImpl(RightMapper rightMapper, UserMapper userMapper,OrgRelationMapper orgRelationMapper,OrgMapper orgMapper) {
        this.rightMapper = rightMapper;
        this.userMapper = userMapper;
        this.orgRelationMapper = orgRelationMapper;
        tree = orgMapper.getChildOrgObject(0);
    }
    @Override
    public List<OrgTree> getPageList(OrgQueryDto dto) {
        return baseMapper.getPageList(dto);
    }
    @Override
    public List<OrgTree> getOrgList(OrgQueryDto dto) {
        return baseMapper.getOrgList(dto);
    }

    @Override
    public List<OrgTree> getChildrenList(OrgQueryDto dto) {
        List<OrgTree> list = baseMapper.getPageList(dto);
        return list;
    }

    @Override
    public List<Map<String, Object>> getDepartmentTree(Map<String, Object> map) {
        List<Map<String, Object>> list = baseMapper.getDepartmentTree(map);
        /*if(list.size() > 0){
            String icon = IconUtil.formatIcon("org");
            if(StringUtil.isNotEmpty(icon)){
                for(Map<String,Object> m : list){

                    m.put("icon",icon);
                }
            }
        }*/
        return list;
    }

    @Override
    public List<OrgTree> getChildOrgObject(int orgId) {
        OrgTree self = OrgUtil.findSelf(tree, orgId);
        return self == null ? new ArrayList<>(0) : self.getChilds();
    }

    @Override
    public List<Org> getRoles() {
        LambdaQueryWrapper<Org> query = new LambdaQueryWrapper<>();
        query.eq(Org::getOrgType,EnumConstant.ORG_TYPE_ROLE);
        query.orderByAsc(Org::getOrgName);
        return list(query);
    }

    @Override
    public List<Map<String, Object>> getOrgTreeByTypeList(Map<String, Object> map, List<Integer> orgTypes) {
        map.put("orgTypeList",orgTypes);
        List<Map<String, Object>> list = baseMapper.getOrgTreeByType(map);
        return list;
    }

    @Override
    public User getUserByOrgId(Integer orgId) {
        QueryWrapper<User> query = new QueryWrapper<>();
        query.eq("orgid",orgId);
        return userMapper.selectOne(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Org saveOrg(OrgDto dto) {
        int pid = dto.getPid();
        Org org = new Org();
        BeanUtils.copyProperties(dto,org);

        int orgId = NumberUtil.safeToInteger(org.getOrgId(),0);
        org.setOrgType(2);
        if(orgId > 0){
            this.updateById(org);
        }else{
            this.save(org);
        }
        OrgRelation relation = new OrgRelation();
        relation.setFromId(pid);
        relation.setToId(org.getOrgId());
        this.deleteOrgRelation(pid,relation.getToId());
        orgRelationMapper.insert(relation);
        this.refreshCache();
        return org;
    }

    @Override
    public void saveRole(Org org) {
        org.setOrgType(EnumConstant.ORG_TYPE_ROLE);
        if(NumberUtil.upper0(org.getOrgId())){
            updateById(org);
        }else{
            save(org);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDragOrg(OrgDragDto dto) {
        OrgRelation relation = new OrgRelation();
        relation.setFromId(dto.getOldPid());
        relation.setToId(dto.getId());
        this.deleteOrgRelation(relation.getFromId(),relation.getToId());
        relation.setFromId(dto.getPid());
        this.deleteOrgRelation(relation.getFromId(),relation.getToId());
        orgRelationMapper.insert(relation);
        RightUtil.refreshMenuCache();
        this.refreshCache();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrgRelation(List<OrgRelation> data) {
        for (OrgRelation relation : data) {
            orgRelationMapper.insert(relation);
        }
        //刷新权限缓存
        RightUtil.refreshMenuCache();
        //刷新组织架构缓存
        this.refreshCache();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrg(List<Integer> ids) {
        if(ObjectUtil.isNotEmpty(ids)){
            removeByIds(ids);
            for(Integer id:ids){
                //删除组织架构关系
                orgRelationMapper.deleteOrgRelationByOrgId(id);
                //删除权限数据
                rightMapper.deleteRightByOrgId(id);
            }
            //刷新权限缓存
            RightUtil.refreshMenuCache();
            //刷新组织架构缓存
            this.refreshCache();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrgRelation(OrgRelationDelDto dto) {
        for (Integer to : dto.getOrgIds()) {
            this.deleteOrgRelation(dto.getPid(),to);
        }
        //刷新权限缓存
        RightUtil.refreshMenuCache();
        //刷新组织架构缓存
        this.refreshCache();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrgRelation(int fromId, int toId) {
        LambdaUpdateWrapper<OrgRelation> w = new LambdaUpdateWrapper<>();
        w.eq(OrgRelation::getFromId,fromId);
        w.eq(OrgRelation::getToId,toId);
        int n = orgRelationMapper.delete(w);
        log.warn("删除OrgRelation{fromId={},toId={}}，条数：{}",fromId,toId,n);
    }

    @Override
    public List<OrgTree> getMainTree() {
        return JSON.parseArray(JSON.toJSONString(tree),OrgTree.class);
    }

    @Override
    public List<OrgTree> getOrgTree(int orgType) {
        return baseMapper.getOrgTree(orgType,0);
    }

    @Override
    public List<Integer> findChildDistinctUserId(int orgId) {
        List<Integer> userIdList = new ArrayList<>(20);
        OrgTree t = findSelf(tree,orgId);
        if(t != null){
            if(EnumConstant.ORG_TYPE_USER.equals(t.getOrgType())){
                userIdList.add(t.getUserId());
            }else if(t.getChilds() != null && t.getChilds().size() > 0){
                this.readUser(t.getChilds(),userIdList,1);
            }
        }
        return userIdList;
    }

    @Override
    public List<Integer> getChildDistinctUserOrgId(int orgId) {
        List<Integer> userIdList = new ArrayList<>(20);
        OrgTree t = findSelf(tree,orgId);
        if(t != null && t.getChilds() != null && t.getChilds().size() > 0){
            this.readUser(t.getChilds(),userIdList,2);
        }
        return userIdList;
    }

    @Override
    public List<Integer> getAllParentOrgId(int orgId) {
        List<OrgTree> s = baseMapper.getParentOrgObject(orgId);
        Set<Integer> res = new HashSet<>(1);
        res.add(orgId);
        this.readOrgId(s,res);
        return new ArrayList<>(res);
    }

    @Override
    public List<User> findChildDistinctUser(int orgId) {
        List<Integer> userIdList = findChildDistinctUserId(orgId);
        if(userIdList.size() > 0){
            return userMapper.selectBatchIds(userIdList);
        }else{
            return new ArrayList<>(0);
        }
    }

    @Override
    public List<User> getChildDistinctUserByOrgType(int orgType, int orgId) {
        List<User> r ;
        if(orgType == EnumConstant.ORG_TYPE_USER){
            User user = getUserByOrgId(orgId);
            r = Collections.singletonList(user);
        }else{
            r = findChildDistinctUser(orgId);
        }
        return r;
    }

    @Override
    public List<OrgTree> getParentOrgObject(int orgId) {
        return baseMapper.getParentOrgObject(orgId);
    }

    @Override
    public List<OrgTree> findLatestParentCache(int orgId) {
        return findLatestParent(this.tree,orgId);
    }

    /**
     * 找到直属上级部门
     */
    private List<OrgTree> findLatestParent(List<OrgTree> list,int orgId){
        List<OrgTree> l = new ArrayList<>();
        for (OrgTree t : list) {
            List<OrgTree> cs = t.getChilds();
            if(ObjectUtil.isNotEmpty(cs)){
                if(inNextChild(cs,orgId)){
                    l.add(t);
                }
                l.addAll(findLatestParent(cs,orgId));
            }

        }
        return l;
    }

    private boolean inNextChild(List<OrgTree> list,int orgId){
        if(list != null && list.size() > 0){
            for (OrgTree t : list) {
                if(Objects.equals(t.getOrgId(),orgId)){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public OrgTree getOrgObject(int orgId) {
        List<OrgTree> list = baseMapper.getOrgObject(orgId);
        return list.size() > 0 ? list.get(0) : null;
    }

    @Override
    public OrgTree findOrgObject(Integer orgId) {
        if(orgId != null && orgId > 0){
            OrgTree self = OrgUtil.findSelf(this.tree, orgId);
            return self;
        }
        return null;
    }

    @Override
    public List<Org> getOrgObjects(List<Integer> orgIds) {
        return baseMapper.selectBatchIds(orgIds);
    }

    @Override
    public void refreshCache() {
        tree = baseMapper.getChildOrgObject(0);
    }

    @Override
    public List<OrgTree> getCacheTree() {
        return tree;
    }

    @Override
    public List<Integer> getOrgUser() {
        List<Integer> s = new LinkedList<>();
        for (OrgTree t : this.tree) {
            List<Integer> userIds = this.findChildDistinctUserId(t.getOrgId());
            s.addAll(userIds);
        }
        return s;
    }

    private OrgTree findSelf(List<OrgTree> trees,int orgId){
        OrgTree r = null;
        for (OrgTree c : trees) {
            if(orgId == c.getOrgId()){
                return c;
            }
            if(c.getChilds() != null && c.getChilds().size() > 0){
                r = findSelf(c.getChilds(),orgId);
                if(r != null){
                    return r;
                }
            }
        }
        return r;
    }
    private void readUser(List<OrgTree> treeList,List<Integer> tmp,int type){
        for(OrgTree tree : treeList){
            if(EnumConstant.ORG_TYPE_USER.equals(tree.getOrgType()) && !tmp.contains(tree.getUserId())){
                tmp.add(type == 1 ? tree.getUserId() : tree.getOrgId());
            }
            List<OrgTree> list = tree.getChilds();
            if(list != null && list.size() > 0){
                readUser(list,tmp,type);
            }
        }
    }
    private void readOrgId(List<OrgTree> treeList, Set<Integer> tmp){
        for(OrgTree tree : treeList){
            tmp.add(tree.getOrgId());
            List<OrgTree> list = tree.getChilds();
            if(list != null && list.size() > 0){
                readOrgId(list,tmp);
            }
        }
    }

}
